home *** CD-ROM | disk | FTP | other *** search
- ; $Id: mylinsys.pro,v 1.13 1997/04/22 17:12:33 rob Exp $
- ;
- ; Copyright (c) 1997, Research Systems, Inc. All rights reserved.
- ; Unauthorized reproduction prohibited.
- ;+
- ; FILE:
- ; mylinsys.pro
- ;
- ; PURPOSE:
- ; This file contains an Analysis PlugIn that computes the
- ; solution of an N-by-N linear system of equations using
- ; one of three methods.
- ;
- ; CONTENTS:
- ; GENERAL ROUTINES
- ; pro HandleEventsMylinsys - handle dialog box events
- ;
- ; CALLBACK ROUTINES
- ; fun ApplyMyLinSys - Apply/OK entry point
- ; fun PromptUserMyLinSys - main entry point (creates dialog)
- ;
- ; REGISTRATION FUNCTION
- ; fun MyLinSys - registers the PlugIn
- ;
- ;-
-
- FORWARD_FUNCTION NORM
-
- ; *****************************************************************************
- ; GENERAL ROUTINES
- ; *****************************************************************************
-
- ; -----------------------------------------------------------------------------
- ;
- ; Purpose: Handle dialog events.
- ;
- pro HandleEventsMyLinSys, sEvent
-
- ; Widget state information.
- ;
- common MyLinSysCommon, psState
- wGroup = (*psState).wMainBase
-
- ; Catch errors.
- ;
- CATCH, error
- if (error ne 0) then begin
- CATCH, /CANCEL
- void = DIALOG_MESSAGE(!ERR_STRING, DIALOG_PARENT=wGroup)
- RETURN
- endif
-
- ; ========================
- ; PROCESS EVENTS
- ; ========================
-
- case (sEvent.id) of
-
- ; --------------------------------------
- ; Array Input text
- ; --------------------------------------
- (*psState).wArrayInputText: begin
-
- ; (nothing to do now)
-
- end
-
- ; --------------------------------------
- ; Vector Input text
- ; --------------------------------------
- (*psState).wVectorInputText: begin
-
- ; (nothing to do now)
-
- end
-
- ; --------------------------------------
- ; Input browse button for 2D array
- ; --------------------------------------
- (*psState).wArrayInputBrowseButton: begin
-
- ; Let user browser for an array data name.
- ;
- void = INSGET( $
- NAME=inputArrayName, $ ; returned name of data selected
- /EXCLUSIVE, $ ; only one selection
- TITLE='Select an array.', $ ; title of browser
- DIMS_LIST=2, $ ; show 2D array data only
- COUNT=count, $ ; returned count of items selected
- GROUP=wGroup, $ ; widget group leader
- _EXTRA=(*psState).extra) ; extra information
-
- ; If user selected an item, set data name in text widget.
- ;
- if (count eq 1) then $
- WIDGET_CONTROL, (*psState).wArrayInputText, $
- SET_VALUE=inputArrayName
- end
-
- ; --------------------------------------
- ; Input browse button for 1D vector
- ; --------------------------------------
- (*psState).wVectorInputBrowseButton: begin
-
- ; Let user browser for a vector data name.
- ;
- void = INSGET( $
- NAME=inputVectorName, $ ; returned name of data selected
- /EXCLUSIVE, $ ; only one selection
- TITLE='Select a vector.', $ ; title of browser
- DIMS_LIST=1, $ ; show 1D array data only
- COUNT=count, $ ; returned count of items selected
- GROUP=wGroup, $ ; widget group leader
- _EXTRA=(*psState).extra) ; extra information
-
- ; If user selected an item, set data name in text widget.
- ;
- if (count eq 1) then $
- WIDGET_CONTROL, (*psState).wVectorInputText, $
- SET_VALUE=inputVectorName
- end
-
- ; --------------------------------------
- ; Method bgroup
- ; --------------------------------------
- (*psState).wLinSysBgroup: begin
-
- WIDGET_CONTROL, (*psState).wLinSysBgroup, GET_VALUE=value
- (*psState).LinSysMethod = value
- end
-
- ; --------------------------------------
- ; Double bgroup
- ; --------------------------------------
- (*psState).wDoubleBgroup: begin
-
- WIDGET_CONTROL, (*psState).wDoubleBgroup, GET_VALUE=value
- (*psState).DoubleMethod = value
- end
-
- ; --------------------------------------
- ; Summary bgroup
- ; --------------------------------------
- (*psState).wSummaryBgroup: begin
-
- WIDGET_CONTROL, (*psState).wSummaryBgroup, GET_VALUE=value
- (*psState).SummaryMethod = value
- end
-
- ; --------------------------------------
- ; OK/Apply/Cancel buttons
- ; --------------------------------------
- (*psState).wOKApplyCancelButtons: begin
-
- ; Destroy dialog on successful OK selection, or if user canceled.
- ;
- if ((sEvent.type eq 'OK') or $
- (sEvent.type eq 'Cancel')) then $
- WIDGET_CONTROL, (*psState).wMainBase, /DESTROY
- end
-
- ; --------------------------------------
- ; other events
- ; --------------------------------------
- else: ; (do nothing)
-
- endcase
-
- end ; HandleEventsMyLinSys
-
- ; *****************************************************************************
- ; CALLBACK ROUTINES
- ; *****************************************************************************
-
- ; -----------------------------------------------------------------------------
- ;
- ; Purpose: Get data and solve linear system.
- ; Fuction returns 1B on success, else 0B.
- ;
- function ApplyMyLinSys, $
- CIDs=CIDs, $ ; OUT: command ID list from INSPUT/INSVIS calls
- _EXTRA=extra ; IN: information to pass to commands
-
- ; Widget state information.
- ;
- common MyLinSysCommon, psState
- wGroup = (*psState).wMainBase
-
- ; ---------------------------------------------------------
- ; Catch errors.
- ; ---------------------------------------------------------
-
- CATCH, error
- if (error ne 0) then begin
- CATCH, /CANCEL
- void = DIALOG_MESSAGE(!ERR_STRING, DIALOG_PARENT=wGroup)
- RETURN, 0B
- endif
-
- ; ---------------------------------------------------------
- ; Check inputs.
- ; ---------------------------------------------------------
-
- ; Get and check array input data name.
- ;
- WIDGET_CONTROL, (*psState).wArrayInputText, GET_VALUE=inputArrayName
- inputArrayName = inputArrayName[0]
- if (inputArrayName eq '') then $
- MESSAGE, 'Must specify Array Input data.', /NONAME
-
- ; Get array input data.
- ;
- inputArrayData = INSGET( $
- inputArrayName, $ ; name of array data to get
- COUNT=count, $ ; returned number of items found
- DIMS_LIST=2, $ ; data should have this dimensionality
- GROUP=wGroup, $ ; widget group leader
- _EXTRA=extra) ; extra information
-
- ; Return if data not found (INSGET displays own error messages).
- ;
- if (count ne 1) then $
- RETURN, 0B
-
- ; Get and check vector input data name.
- ;
- WIDGET_CONTROL, (*psState).wVectorInputText, GET_VALUE=inputVectorName
- inputVectorName = inputVectorName[0]
- if (inputVectorName eq '') then $
- MESSAGE, 'Must specify Vector Input data.', /NONAME
-
- ; Get vector input data.
- ;
- inputVectorData = INSGET( $
- inputVectorName, $ ; name of vector data to get
- COUNT=count, $ ; returned number of items found
- DIMS_LIST=1, $ ; data should have this dimensionality
- GROUP=wGroup, $ ; widget group leader
- _EXTRA=extra) ; extra information
-
- ; Return if data not found (INSGET displays own error messages).
- ;
- if (count ne 1) then $
- RETURN, 0B
-
- ; Check input data for correct size.
- ; The array must be square.
- ; The array column dimension must match the vector length.
- ;
- aDim = SIZE(inputArrayData)
- vDim = SIZE(inputVectorData)
- if (aDim[1] ne aDim[2]) then $
- MESSAGE, 'Array Input must be square.', /NONAME
- if (aDim[2] ne vDim[vDim[0]+2]) then $
- MESSAGE, 'Array Input and Vector Input are of incompatible size. ' $
- + 'Select a Vector Input with a length of ' $
- + STRCOMPRESS(STRING(aDim[2]), /REMOVE_ALL) + '.', /NONAME
-
- ; ---------------------------------------------------------
- ; Compute the solution using one of three methods.
- ; ---------------------------------------------------------
-
- ; Put up wait cursor.
- ;
- WIDGET_CONTROL, (*psState).wMainBase, /HOURGLASS
-
- start = SYSTIME(1)
-
- ; Use Biconjugate Gradient.
- ;
- if ((*psState).LinSysMethod eq 0) then begin
-
- newData = LINBCG(SPRSIN(inputArrayData, $
- DOUBLE=(*psState).DoubleMethod), inputVectorData, $
- REPLICATE(MEDIAN(inputVectorData, /EVEN), $
- N_ELEMENTS(inputVectorData)), $
- ITOL=1, DOUBLE=(*psState).DoubleMethod)
-
- ; Use LU decomposition.
- ;
- endif else if ((*psState).LinSysMethod eq 1) then begin
-
- LUDC, inputArrayData, index, DOUBLE=(*psState).DoubleMethod
-
- newData = LUSOL(inputArrayData, index, inputVectorData, $
- DOUBLE=(*psState).DoubleMethod)
-
- ; Get "fresh" copy of Array Input data.
- ;
- inputArrayData = INSGET( $
- inputArrayName, $
- COUNT=count, $
- DIMS_LIST=2, $
- GROUP=wGroup, $
- _EXTRA=extra)
-
- ; Use SV decomposition.
- ;
- endif else begin
-
- SVDC, inputArrayData, w, u, v, DOUBLE=(*psState).DoubleMethod
-
- newData = SVSOL(u, w, v, inputVectorData, $
- DOUBLE=(*psState).DoubleMethod)
-
- endelse
-
- stop = SYSTIME(1)
-
- ; ---------------------------------------------------------
- ; Put the solution into the Insight Data Manager.
- ; ---------------------------------------------------------
-
- description = 'LinSys ' + inputVectorName
-
- outputName = (*psState).outputName
-
- INSPUT, $
- newData, $ ; the data
- DESCRIPTION=description, $ ; data description
- NAME=outputName, $ ; use this data name
- COUNT=count, $ ; returned # of items put
- CIDs=CIDs, $ ; command ID list
- GROUP=wGroup, $ ; widget group leader
- _EXTRA=extra ; extra information
-
- ; Return if "put" failed.
- ;
- if (count ne 1) then $
- RETURN, 0B
-
- ; ---------------------------------------------------------
- ; Put the residual into Insight (Data Manager).
- ; ---------------------------------------------------------
- description = 'Residual ' + inputVectorName
-
- resName = 'LinSys Residual'
-
- resData = TRANSPOSE(inputArrayData ## newData - inputVectorData)
-
- INSPUT, $
- resData, $ ; the data
- DESCRIPTION=description, $ ; data description
- NAME=resName, $ ; try this data name
- NEW_NAME=resNameUsed, $ ; the data name actually used
- REPLACE=2, $ ; prompt user if name conflict
- COUNT=count, $ ; returned # of items put
- CIDs=CIDs, $ ; command ID list
- GROUP=wGroup, $ ; widget group leader
- _EXTRA=extra ; extra information
-
- ; Return if "put" failed.
- ;
- if (count ne 1) then $
- RETURN, 0B
-
- ; ---------------------------------------------------------
- ; Visualize the residual (error plot).
- ; ---------------------------------------------------------
-
- INSVIS, $
- resNameUsed, $ ; name of data item
- TYPE='plot', $ ; visualization type
- MODE='new', $ ; insert | new | overlay
- CIDs=CIDs, $ ; command ID list
- GROUP=wGroup, $ ; widget group leader
- _EXTRA=extra ; extra information
-
- ; ---------------------------------------------------------
- ; Create a summary box.
- ; ---------------------------------------------------------
-
- if ((*psState).SummaryMethod eq 1) then begin
-
- msg1 = 'Residual Norm: |Ax - b| =' + $
- STRING(NORM(resData, DOUBLE=(*psState).DoubleMethod))
- msg2 = 'Method Timing:' + STRING(FLOAT(stop-start)) + ' Seconds'
-
- void = DIALOG_MESSAGE([[msg1], [msg2]], /INFORMATION, $
- TITLE='Linear Systems Summary', $
- DIALOG_PARENT=(*psState).wMainBase)
- endif
-
- ; ---------------------------------------------------------
- ; Successful return.
- ; ---------------------------------------------------------
-
- RETURN, 1B
-
- end ; ApplyMyLinSys
-
- ; -----------------------------------------------------------------------------
- ;
- ; Purpose: Main entry point for the PlugIn.
- ;
- pro PromptUserMyLinSys, $
- GROUP=wGroup, $ ; IN: group leader widget ID
- _EXTRA=extra ; IN: various information
-
- ; Widget state information.
- ;
- common MyLinSysCommon, psState
-
- ; Create modal main base (non-sizable).
- ;
- title = 'Analysis PlugIn - Linear System of Equations'
- wMainBase = WIDGET_BASE(TITLE=title, GROUP_LEADER=wGroup, $
- /COLUMN, /MODAL, /TLB_FRAME_ATTR)
-
- value = [ $
- 'Select a 2D array (A) and a 1D vector (b) that define a', $
- 'Linear System of Equations, Ax = b.', $
- 'The solution (x) is available through the Data Manager.', $
- 'The residual (Ax - b) is displayed as an XY plot.' $
- ]
- for i = 0, N_ELEMENTS(value)-1 do $
- void = WIDGET_LABEL(wMainBase, VALUE=value[i])
-
- ; ------------------------------------------
- ; Create INPUTS widgets.
- ; ------------------------------------------
-
- wInputsBase = WIDGET_BASE(wMainBase, /COLUMN, /FRAME)
-
- void = WIDGET_LABEL(wInputsBase, VALUE='INPUTS')
-
- ; Array Input.
- ;
- wInputDataBase = WIDGET_BASE(wInputsBase, /ROW)
- void = WIDGET_LABEL(wInputDataBase, VALUE='Array Input: ')
- wArrayInputText = WIDGET_TEXT(wInputDataBase, VALUE='', /EDITABLE)
- wArrayInputBrowseButton = $
- WIDGET_BUTTON(wInputDataBase, VALUE=' Browse... ')
-
- ; Vector Input.
- ;
- wInputDataBase = WIDGET_BASE(wInputsBase, /ROW)
- void = WIDGET_LABEL(wInputDataBase, VALUE='Vector Input: ')
- wVectorInputText = WIDGET_TEXT(wInputDataBase, VALUE='', /EDITABLE)
- wVectorInputBrowseButton = $
- WIDGET_BUTTON(wInputDataBase, VALUE=' Browse... ')
-
- wLinSysBase = WIDGET_BASE(wInputsBase, /ROW)
- void = WIDGET_LABEL(wLinSysBase, VALUE='Method: ')
- wLinSysBgroup = CW_BGROUP(wLinSysBase, $
- ['Biconjugate Gradient', 'LU Decomposition', 'SV Decomposition'], $
- /NO_RELEASE, /ROW, /RETURN_NAME, /EXCLUSIVE, SET_VALUE=1)
- LinSysMethod = 1 ; (set default method to LU Decomposition)
-
- wBottomBase = WIDGET_BASE(wMainBase, /ROW)
-
- ; ------------------------------------------
- ; Create OPTIONS widgets.
- ; ------------------------------------------
-
- wOptionsLabelBase = WIDGET_BASE(wBottomBase, /COLUMN, /FRAME)
- void = WIDGET_LABEL(wOptionsLabelBase, VALUE='OPTIONS')
-
- wOptionsBase = WIDGET_BASE(wOptionsLabelBase, /ROW)
-
- wDoubleBgroup = CW_BGROUP(wOptionsBase, 'Double Precision', $
- /NONEXCLUSIVE, SET_VALUE=0)
- DoubleMethod = 0
-
- wSummaryBgroup = CW_BGROUP(wOptionsBase, 'Summary', $
- /NONEXCLUSIVE, SET_VALUE=1)
- SummaryMethod = 1
-
- ; ------------------------------------------
- ; Create OUTPUTS widgets.
- ; ------------------------------------------
-
- outputName = 'LinSys Solution'
-
- wOutputsLabelBase = WIDGET_BASE(wBottomBase, /COLUMN, /FRAME)
- void = WIDGET_LABEL(wOutputsLabelBase, VALUE='OUTPUTS')
-
- wOutputsBase = WIDGET_BASE(wOutputsLabelBase, /ROW)
-
- void = WIDGET_LABEL(wOutputsBase, $
- VALUE=' Vector Output: '+outputName)
-
- ; ------------------------------------------
-
- ; Create OK/Apply/Cancel buttons using special compound widget.
- ; (Must pass in main modal base, used to set default and cancel buttons.)
- ;
- wOKApplyCancelButtons = CW_INSAPPLY(wMainBase, _EXTRA=extra)
-
- ; Create dialog state information.
- ;
- sState = { $
- extra: extra, $
- wMainBase: wMainBase, $
- outputName: outputName, $
- wArrayInputText: wArrayInputText, $
- wArrayInputBrowseButton: wArrayInputBrowseButton, $
- wVectorInputText: wVectorInputText, $
- wVectorInputBrowseButton: wVectorInputBrowseButton, $
- wLinSysBgroup: wLinSysBgroup, $
- LinSysMethod: LinSysMethod, $
- wOKApplyCancelButtons: wOKApplyCancelButtons, $
- wDoubleBgroup: wDoubleBgroup, $
- DoubleMethod: DoubleMethod, $
- wSummaryBgroup: wSummaryBgroup, $
- SummaryMethod:SummaryMethod $
- }
-
- ; Store the state in a heap variable.
- ;
- psState = PTR_NEW(sState, /NO_COPY)
-
- ; Realize the dialog box.
- ;
- WIDGET_CONTROL, wMainBase, /REALIZE
-
- ; Start event loop.
- ;
- XMANAGER, 'PromptUserMyLinSys', wMainBase, $
- EVENT_HANDLER='HandleEventsMyLinSys'
-
- ; Remove widget state info.
- ;
- PTR_FREE, psState
-
- end ; PromptUserMyLinSys
-
- ; *****************************************************************************
- ; REGISTRATION FUNCTION
- ; *****************************************************************************
-
- ; -----------------------------------------------------------------------------
- ;
- ; Purpose: Register the Analysis PlugIn.
- ;
- function MyLinSys
-
- ; Return the Analysis PlugIn Registration Structure.
- ;
- RETURN, { $
- type: 'Analysis_PlugIn', $ ; PlugIn type
- title: 'My LinSys...', $ ; PlugIn type
- purpose: 'Solve linear systems.', $ ; PlugIn purpose
- main_proc: 'PromptUserMyLinSys', $ ; main callback
- apply_func: 'ApplyMyLinSys', $ ; apply callback
- version: '5.0', $ ; IDL version
- revision: '1.0' $ ; PlugIn version
- }
-
- end ; MyLinSys
-
- ; -----------------------------------------------------------------------------
-